extends Node2D
class_name BaseGrid
enum TYPE {
	BAN_BUILD,
	CAN_BUILD
}

signal on_visible_ban_cell(value : bool)

@export var cell_size : Vector2i = Vector2(64,64)
@export var grid_xy : Vector2i = Vector2(13,13)

const BASE_CELL_PRE = preload("res://grid/base_cell.tscn")
const SPACE : Vector2i = Vector2(4,4)
const MODEL_TYPE : Dictionary = {
	TYPE.BAN_BUILD : preload("uid://cty4ewevnsk3r"),
	TYPE.CAN_BUILD : preload("res://asset/cell_type/can.png")
}

var astar_grid = AStarGrid2D.new()
var cell_dic : Dictionary
var random_lib : Array[Vector2i]
var block_dic : Dictionary

func _ready() -> void:
	_init_pos()
	_create_grid()
	_init_astar_grid()

func _init_pos() -> void :
	global_position.x -= (grid_xy.x - 1) * (cell_size.x + SPACE.x) * 0.5
	global_position.y -= (grid_xy.y - 1) * (cell_size.y + SPACE.y) * 0.5

func _init_texture() -> void :
	for value in MODEL_TYPE.values() :
		value.texture.width = cell_size.x
		value.texture.height = cell_size.y

func _create_grid() :
	cell_dic.clear()
	for y in grid_xy.y :
		for x in grid_xy.x :
			var cell = BASE_CELL_PRE.instantiate()
			var cell_xy = Vector2i(x,y)
			cell._init_model(cell_xy)
			cell._init_pos(SPACE + cell_size)
			on_visible_ban_cell.connect(cell._visible_ban_cell)
			cell.cell_type = TYPE.CAN_BUILD if (to_global(cell.position)).length() < cell_size.length() * 1.5 else TYPE.BAN_BUILD
			add_child(cell)
			cell_dic.set((grid_xy / 2 - cell_xy) * -1,cell)
			if y == 0 or y == grid_xy.y - 1 :
				random_lib.append(cell_xy)
			if y > 0 and y < grid_xy.y - 1 and (x == 0 or x == grid_xy.x - 1) :
				random_lib.append(cell_xy)


func _init_astar_grid() -> void :
	astar_grid.region = Rect2i(-grid_xy, grid_xy * 2)
	astar_grid.cell_size = cell_size + SPACE
	astar_grid.default_compute_heuristic = AStarGrid2D.HEURISTIC_OCTILE
	astar_grid.default_estimate_heuristic = AStarGrid2D.HEURISTIC_OCTILE
	astar_grid.diagonal_mode = AStarGrid2D.DIAGONAL_MODE_NEVER
	astar_grid.update()
	GlobalVariable.astar_grid = astar_grid
	astar_grid.set_point_solid(Vector2i(0,0))

func _get_random_maker_xy() -> Vector2i :
	return random_lib.pick_random() - (grid_xy - Vector2i.ONE) / 2

func _get_cell_xy(pos : Vector2) :
	var block_size = cell_size + SPACE
	var local_pos = Vector2i(to_local(pos)) + (block_size / 2)
	if local_pos.x < 0 or local_pos.y < 0 : return null
	var local_xy = Vector2i(local_pos.x / block_size.x,local_pos.y / block_size.y)
	return (grid_xy / 2 - local_xy) * -1

func _get_cell(pos : Vector2) -> BaseCell :
	var local_xy = _get_cell_xy(pos)
	return cell_dic.get(local_xy)

func _get_pos(xy : Vector2i) -> Vector2 :
	var cell = cell_dic.get(xy)
	return cell.global_position

func _set_block(pos : Vector2, block_list : Array[Vector2i]) -> bool :
	var local_xy = _get_cell_xy(pos)
	if local_xy == null : return false
	var save_block_list = {}
	for block in block_list :
		var block_xy = local_xy + block
		var cell = cell_dic.get(block_xy)
		if not cell : return false
		save_block_list.set(block_xy,1)
	for block in save_block_list :
		astar_grid.set_point_solid(block)
		block_dic.set(block,1)
	return true

func _remove_block(_xy : Vector2i, value : bool = false) -> void :
	var target_xy = (grid_xy / 2 - _xy) * -1
	block_dic.erase(target_xy)
	astar_grid.set_point_solid(target_xy,value)

func _check_disable_build(_xy : Vector2i) -> bool :
	var target_xy = (grid_xy / 2 - _xy) * -1
	var result = astar_grid.is_point_solid(target_xy)
	return result

func _reset_able_build_area(size : int) -> void :
	for cell in cell_dic.values() :
		if (to_global(cell.position)).length() < cell_size.length() * size :
			if not cell.cell_type == TYPE.CAN_BUILD :
				cell._reset_cell_type(TYPE.CAN_BUILD)
		else :
			cell._reset_cell_type(TYPE.BAN_BUILD)

func _reset_able_build_cell(pos : Vector2, is_check : bool, block : Area2D = null) -> bool :
	var cell = _get_cell(pos)
	if not cell : return false
	if cell._check_disable_build() :
		if is_check :
			block.global_position = cell.global_position
			return true
		cell._reset_cell_type(BaseGrid.TYPE.CAN_BUILD)
		return true
	return false
